#include "write_blf.h"

Writeblf::Writeblf(const char* file) :file_name_(file),file_start_time_(0){
    mtx_ = std::make_shared<std::mutex>();
}

Writeblf::~Writeblf() {
    file_start_time_ = 0;
};

int32_t Writeblf::StartWriteBlf() {
    std::lock_guard lock(*mtx_);
    file_.open(file_name_, std::ios_base::out);  //in:read  out:write
    if (!file_.is_open()) {
        return -1;
    }
    // write start time
    auto now = std::chrono::system_clock::now();
    std::time_t time = std::chrono::system_clock::to_time_t(now);
    std::tm *tm = std::localtime(&time);
    file_.fileStatistics.measurementStartTime.year = tm->tm_year + 1900;
    file_.fileStatistics.measurementStartTime.month = tm->tm_mon + 1;
    file_.fileStatistics.measurementStartTime.day = tm->tm_mday;
    file_.fileStatistics.measurementStartTime.dayOfWeek = tm->tm_wday;
    file_.fileStatistics.measurementStartTime.hour = tm->tm_hour;
    file_.fileStatistics.measurementStartTime.minute = tm->tm_min;
    file_.fileStatistics.measurementStartTime.second = tm->tm_sec;
    file_start_time_ = std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::system_clock::now()).time_since_epoch().count();
    return 0;
}

bool Writeblf::FileStat() {
    return file_.is_open();
}

int32_t Writeblf::BlfWriteCanData(CanData frame) {
    std::lock_guard lock(*mtx_);
    if (! file_.is_open()) return -1;
    if ((frame.type_flag & CAN_FRAME_DATA) == CAN_FRAME_DATA) {
        auto * can_msg = new Vector::BLF::CanMessage;
        can_msg->channel = frame.channel;
        can_msg->flags &= 0x00;
        if ((frame.type_flag & CAN_FRAME_REMOTE) == CAN_FRAME_REMOTE) {
            can_msg->flags |= 0x80;
        }
        if ((frame.type_flag & CAN_ID_EXT) == CAN_ID_EXT) {
            can_msg->flags |= 0x08;
        }
        can_msg->dlc = frame.data_len;
        can_msg->id = frame.id;
        for(int i = 0 ; i < frame.data_len ; i++)
            can_msg->data[i] = frame.data[i];
        can_msg->objectTimeStamp = frame.time - file_start_time_;
        // can_msg->objectTimeStamp = frame.time;
        can_msg->objectFlags = Vector::BLF::ObjectHeader::ObjectFlags::TimeTenMics;
        file_.write(can_msg);
    }
    return 0;
}

int32_t Writeblf::BlfWriteCanfdData(CanData frame) {
    std::lock_guard lock(*mtx_);
    if (! file_.is_open()) return -1;
    if ((frame.type_flag & CAN_FRAME_DATA) == CAN_FRAME_DATA) {
        auto * canfd_msg = new Vector::BLF::CanFdMessage64;
        canfd_msg->channel = frame.channel;
        switch (frame.data_len) {
            case 0:
            case 1:
            case 2:
            case 3:
            case 4:
            case 5:
            case 6:
            case 7:
            case 8:
                canfd_msg->dlc = frame.data_len;
            break;
            case 12:
                canfd_msg->dlc = 9;
            break;
            case 16:
                canfd_msg->dlc = 10;
            break;
            case 20:
                canfd_msg->dlc = 11;
            break;
            case 24:
                canfd_msg->dlc = 12;
            break;
            case 32:
                canfd_msg->dlc = 13;
            break;
            case 48:
                canfd_msg->dlc = 14;
            break;
            case 64:
                canfd_msg->dlc = 15;
            break;
            default:
                break;
        }
        canfd_msg->validDataBytes = frame.data_len;
        canfd_msg->txCount = 0;
        canfd_msg->id = frame.id;
        canfd_msg->flags &= 0x0000;
        if (frame.type_flag & CAN_EN_BRS)
            canfd_msg->flags |= 0x2000;     // BRS
        if (frame.type_flag & CAN_EN_FD)
            canfd_msg->flags |= 0x1000;     // EDL
        if (frame.type_flag & CAN_ID_EXT) {
            canfd_msg->flags |= 0x0200;     // SRR
        }
        canfd_msg->bitCount = 0;
        canfd_msg->frameLength = frame.data_len;
        canfd_msg->btrCfgArb = 0;//1 * 1000 * 1000;
        canfd_msg->btrCfgData = 0;//5 * 1000 * 1000;
        canfd_msg->timeOffsetBrsNs = 0;//500;
        canfd_msg->timeOffsetCrcDelNs = 0;//200;
        canfd_msg->dir = 1;
        // ext frame need set
        canfd_msg->extDataOffset = 0;
        canfd_msg->crc = 0;
        canfd_msg->objectTimeStamp = frame.time - file_start_time_;
        // canfd_msg->objectTimeStamp = frame.time;
        canfd_msg->objectFlags = Vector::BLF::ObjectHeader::ObjectFlags::TimeTenMics;
        canfd_msg->data.clear();
        for(int i = 0 ; i < frame.data_len ; i++) {
            canfd_msg->data.push_back(frame.data[i]);
        }
        file_.write(canfd_msg);
    }
    return 0;
}

int32_t Writeblf::BlfWriteFlexrayData(const FlexrayData& frame){
    std::lock_guard lock(*mtx_);
    if (! file_.is_open()) return -1;
    auto *flexray_msg = new Vector::BLF::FlexRayVFrReceiveMsgEx;
    flexray_msg->dataBytes.clear();
    flexray_msg->channel = frame.channel;
    flexray_msg->channelMask = frame.channel_mask;
    flexray_msg->frameId = frame.message_id;
    flexray_msg->byteCount = frame.byte_count;
    flexray_msg->dataCount = frame.data_bytes;
    flexray_msg->version = 0;
    flexray_msg->dir = 0;               // Tx
    flexray_msg->clientIndex = 0;
    flexray_msg->clusterNo = 0;
    flexray_msg->headerCrc1 = frame.headerCrc1;
    flexray_msg->headerCrc2 = frame.headerCrc2;
    flexray_msg->cycle = frame.cycle_number;
    flexray_msg->tag = frame.tag;
    flexray_msg->data = 0x0;
    flexray_msg->frameFlags = frame.frame_flags;
    flexray_msg->appParameter = 0;
    flexray_msg->frameCrc = frame.frame_crc;
    flexray_msg->frameLengthNs = 0;
    flexray_msg->frameId1 = 0;
    flexray_msg->pduOffset = 0;
    flexray_msg->blfLogMask = 0;
    flexray_msg->dataBytes = frame.data;
    flexray_msg->objectTimeStamp = frame.time - file_start_time_;
    // flexray_msg->objectTimeStamp = frame.time;
    flexray_msg->objectFlags = Vector::BLF::ObjectHeader::ObjectFlags::TimeTenMics;
    file_.write(flexray_msg);
    return 0;
}

int32_t Writeblf::EndWriteBlf() {
    std::lock_guard lock(*mtx_);
    // write end time
    if (! file_.is_open()) return -1;
    auto now = std::chrono::system_clock::now();
    auto time = std::chrono::system_clock::to_time_t(now);
    auto tm = std::localtime(&time);
    file_.fileStatistics.lastObjectTime.year = tm->tm_year + 1900;
    file_.fileStatistics.lastObjectTime.month = tm->tm_mon + 1;
    file_.fileStatistics.lastObjectTime.day = tm->tm_mday;
    file_.fileStatistics.lastObjectTime.dayOfWeek = tm->tm_wday;
    file_.fileStatistics.lastObjectTime.hour = tm->tm_hour;
    file_.fileStatistics.lastObjectTime.minute = tm->tm_min;
    file_.fileStatistics.lastObjectTime.second = tm->tm_sec;
    file_.close();
    return 0;
}
